package com.xuecheng.content.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xuecheng.base.exception.CommonError;
import com.xuecheng.base.exception.XuechengPlusException;
import com.xuecheng.base.utils.StringUtil;
import com.xuecheng.content.config.MultipartSupportConfig;
import com.xuecheng.content.feignclient.MediaServiceClient;
import com.xuecheng.content.mapper.*;
import com.xuecheng.content.model.dto.CourseBaseInfoDto;
import com.xuecheng.content.model.dto.CoursePreviewDto;
import com.xuecheng.content.model.dto.TeachplanDto;
import com.xuecheng.content.model.po.*;
import com.xuecheng.content.service.CourseBaseInfoService;
import com.xuecheng.content.service.CoursePublishService;
import com.xuecheng.content.service.CourseTeacherService;
import com.xuecheng.content.service.TeachplanService;
import com.xuecheng.messagesdk.model.po.MqMessage;
import com.xuecheng.messagesdk.service.MqMessageService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class CoursePublishServiceImpl implements CoursePublishService {
    @Autowired
    private CourseBaseInfoService courseBaseInfoService;
    @Autowired
    private TeachplanService teachplanService;
    @Autowired
    private CourseTeacherService courseTeacherService;
    @Autowired
    private CoursePublishPreMapper coursePublishPreMapper;
    @Autowired
    private CourseMarketMapper courseMarketMapper;
    @Autowired
    private CourseBaseMapper courseBaseMapper;
    @Autowired
    private CoursePublishMapper coursePublishMapper;
    @Autowired
    private MqMessageService mqMessageService;
    @Autowired
    private MediaServiceClient mediaServiceClient;
    @Autowired
    private TeachplanMediaMapper teachplanMediaMapper;
    @Autowired
    private TeachplanMapper teachplanMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public CoursePreviewDto getCoursePreviewInfo(String courseId) {
        CoursePreviewDto coursePreviewDto = new CoursePreviewDto();
        CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfo(Long.parseLong(courseId));
        List<TeachplanDto> teachplanTree = teachplanService.findTeachplanTree(Long.parseLong(courseId));
        coursePreviewDto.setCourseBase(courseBaseInfo);
        coursePreviewDto.setTeachplans(teachplanTree);
        return coursePreviewDto;
    }

    @Transactional
    @Override
    public void commitAudit(Long companyId, Long courseId) {
        CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfo(courseId);
        if (courseBaseInfo == null) {
            XuechengPlusException.cast("课程为空");
        }
        //约束：
        //本机构只能提交本机构的课程
        if (!companyId.equals(courseBaseInfo.getCompanyId())) {
            XuechengPlusException.cast("本机构只能提交本机构的课程");
        }
        //如果课程状态为已提交，则不允许提交
        String status = courseBaseInfo.getStatus();
        if (status == null || status.equals("202003")) {
            XuechengPlusException.cast("课程状态为空或已提交，不允许再提交");
        }
        //如果课程图片，计划信息不完整，则也不允许提交
        String pic = courseBaseInfo.getPic();
        if (pic == null || StringUtil.isEmpty(pic)) {
            XuechengPlusException.cast("请上传图片");
        }
        List<TeachplanDto> teachplanTree = teachplanService.findTeachplanTree(courseId);
        if (teachplanTree == null || teachplanTree.size() == 0) {
            XuechengPlusException.cast("请上传课程计划");
        }
        //查询课程基本信息，营销信息，师资信息等,将信息插入预发布表
        CoursePublishPre coursePublishPre = new CoursePublishPre();
        List<CourseTeacher> courseTeacher = courseTeacherService.getCourseTeacher(courseId);
        String courseTeacherJSON = JSON.toJSONString(courseTeacher);
        CourseMarket courseMarket = courseMarketMapper.selectById(courseId);
        String courseMarketJSON = JSON.toJSONString(courseMarket);
        String teachplanJSON = JSON.toJSONString(teachplanTree);
        BeanUtils.copyProperties(courseBaseInfo, coursePublishPre);
        coursePublishPre.setMarket(courseMarketJSON);
        coursePublishPre.setTeachplan(teachplanJSON);
        coursePublishPre.setTeachers(courseTeacherJSON);
        coursePublishPre.setStatus("202003");
        coursePublishPre.setCreateDate(LocalDateTime.now());
        CoursePublishPre coursePublishPre1 = coursePublishPreMapper.selectById(courseId);
        if (coursePublishPre1 == null)
            coursePublishPreMapper.insert(coursePublishPre);
        else {
            coursePublishPreMapper.updateById(coursePublishPre1);
        }

        //修改课程基本信息表的审核状态为已提交
        CourseBase courseBase = courseBaseMapper.selectById(courseId);
        courseBase.setAuditStatus("202003");
        courseBaseMapper.updateById(courseBase);
    }

    @Transactional
    @Override
    public void publish(Long companyId, Long courseId) {

        //查询预发布表
        CoursePublishPre coursePublishPre = coursePublishPreMapper.selectById(courseId);
        if (coursePublishPre == null) {
            XuechengPlusException.cast("预发布表为空");
        }
        //约束：
        //课程没通过审核则不允许发布
        String status = coursePublishPre.getStatus();
        if (!status.equals("202004")) {
            XuechengPlusException.cast("审核未通过");
        }
        //本机构只能发布本机构的课程
        if (!companyId.equals(coursePublishPre.getCompanyId())) {
            XuechengPlusException.cast("本机构只能发布本机构的课程");
        }
        //课程中必须有媒资文件
        LambdaQueryWrapper<TeachplanMedia> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TeachplanMedia::getCourseId,courseId);
        int mediaCount = teachplanMediaMapper.selectCount(queryWrapper);
        LambdaQueryWrapper<Teachplan> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(Teachplan::getCourseId,courseId).eq(Teachplan::getGrade,2);
        int techplanCount = teachplanMapper.selectCount(queryWrapper1);
        if(mediaCount!=techplanCount){
            XuechengPlusException.cast("课程中每个小节都必须有媒资文件");
        }

        //将预发布表数据拷贝到发布表
        CoursePublish coursePublish = new CoursePublish();
        BeanUtils.copyProperties(coursePublishPre, coursePublish);
        CoursePublish coursePublish1 = coursePublishMapper.selectById(courseId);
        if (coursePublish1 == null) {
            coursePublishMapper.insert(coursePublish);
        } else {
            coursePublishMapper.updateById(coursePublish);
        }
        //向消息表中写数据
        saveCoursePublishMessage(courseId);
        //删除课程预发布表对应记录
        coursePublishPreMapper.deleteById(courseId);

    }

    private void saveCoursePublishMessage(Long courseId) {
        MqMessage coursePublish = mqMessageService.addMessage("course_publish", String.valueOf(courseId), null, null);
        if (coursePublish == null) {
            XuechengPlusException.cast(CommonError.UNKOWN_ERROR);
        }
    }

    @Override
    public File generateCourseHtml(Long courseId) {
        Configuration configuration = new Configuration(Configuration.getVersion());
        //最终返回的文件
        File htmlFile=null;
        try {
            //拿到classpath路径
            String classPath = this.getClass().getResource("/").getPath();
            //指定模版的路径
            configuration.setDirectoryForTemplateLoading(new File(classPath+"/templates"));
            //指定编码
            configuration.setDefaultEncoding("utf-8");
            //得到模版
            Template template = configuration.getTemplate("course_template.ftl");
            //准备数据
            CoursePreviewDto coursePreviewInfo = this.getCoursePreviewInfo(String.valueOf(courseId));
            HashMap<String, Object> map=new HashMap<>();
            map.put("model",coursePreviewInfo);
            //template模版+map数据=html页面
            String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
            //输入流
            InputStream inputStream = IOUtils.toInputStream(html, "utf-8");
            //输出文件
            htmlFile=File.createTempFile("coursepublish",".html");
            FileOutputStream fileOutputStream = new FileOutputStream(htmlFile);
            //使用流将html写入文件
            IOUtils.copy(inputStream,fileOutputStream);
        }catch (Exception e){
            log.error("页面静态化出现问题，courseId:{}",courseId,e);
            e.getMessage();
        }
        return htmlFile;
    }

    @Override
    public void uploadCourseHtml(Long courseId, File file) {
        //将file转为multipartFile
        MultipartFile multipartFile = MultipartSupportConfig.getMultipartFile(file);
        String upload = mediaServiceClient.upload(multipartFile, "/course/"+courseId+".html");
        if(upload==null){
            log.debug("走熔断降级逻辑得到上传的结果为Null，课程id：{}",courseId);
            XuechengPlusException.cast("上传静态文件存在异常");
        }
    }

    @Override
    public CoursePublish getCoursePublish(Long courseId) {
        CoursePublish coursePublish = coursePublishMapper.selectById(courseId);
        return coursePublish;
    }

    @Override
    public CoursePublish getCoursePublishCache(Long courseId) {
        Object jsonObj = redisTemplate.opsForValue().get("course" + courseId);
        if(jsonObj!=null){
            String jsonString = jsonObj.toString();
            if("null".equals(jsonString))
                return null;
            CoursePublish coursePublish = JSON.parseObject(jsonString, CoursePublish.class);
            return coursePublish;
        }
        else {
            CoursePublish coursePublish = getCoursePublish(courseId);
            redisTemplate.opsForValue().set("course"+courseId,JSON.toJSONString(coursePublish),30, TimeUnit.SECONDS);
            return coursePublish;
        }
    }
}
